/**
* Copyrights 2011 Michal Saman, m.saman@designplus.cz.
* This source code is release under the Apache License 2.0.
* http://www.apache.org/licenses/LICENSE-2.0
*
* @file tsh.h
* @brief Reindeer OS Tiny Shell
*
* Small shell for basic interaction with OS and some basic buildin commands.
*/

#include <env.h>
#include <ctype.h>
#include <stdint.h>
#include <tsh/tsh.h>
#include <main/kprintf.h>

static struct Prompt_info _prompt_info;
static char command_buffer[max_len_com_buffer];

void parse_prompt() {
	_prompt_info.prompt_len = strlen(default_prompt);
	strcpy(_prompt_info.prompt, default_prompt);
}


void print_prompt() {
	vga_text_mode_putc('\n');
	//DebugResetX();
	vga_text_mode_set_color(0xA);
	kprintf(_prompt_info.prompt);
	vga_text_mode_set_color(0xF);
}

/**
 * Function periodically scans keyboard last KEYCODE a return it as output.
 * After KEYCODE is readed, than is discarted.
 * @return enum KEYCODE last pressed key as their KEYCODE value
 */
enum KEYCODE scan_keyboard() {
	enum KEYCODE key = KEY_UNKNOWN;

	while (key == KEY_UNKNOWN) {
		key = kbrd_get_last_key();
	}

	kbrd_discard_last_key();
	return key;
}

void tiny_shell_help() {
	kprintf("Tiny shell v0.1\n\n");
	kprintf("Avaiable commands:\n");
	kprintf("kheap          Show debug information about kernel heap.\n");
	kprintf("kheaptest      Simulates heavy load of kernel heap allocator.\n");
	kprintf("pci            Show emuration of PCI bus.\n");
	kprintf("ata            Show information about connected ATA controllers and devices.\n");
	kprintf("atatest        Tries to write/read to sector 0 at device 0 at channel 0.\n");
	kprintf("reset          Reset the system.\n");
}

/**
 * Start Tiny Shell process.
 */
void tiny_shell_init() {

	uint32_t 	buff_position = 0;
	uint8_t 	prompt_line = 0;

	parse_prompt();
	print_prompt();

	// start scan keyboard...
	while(1) {
		enum KEYCODE key = scan_keyboard();
		switch (key) {
			case KEY_RETURN:
				// terminate command_buffer string
				command_buffer[buff_position] = 0;
				vga_text_mode_putc('\n');
				if (!tsh_exec()) {
					kprintf("tshell: %s: command not found", command_buffer);
				}
				// reset buffer position
				buff_position = 0;
				print_prompt();
				prompt_line = 0;
				break;
			case KEY_BACKSPACE:
				// delete previous character on line
				if (vga_text_mode_cursor_getX() >= _prompt_info.prompt_len && prompt_line==0) {
					vga_text_mode_putc(kbrd_key_to_ascii(key));
					if (buff_position>0)
						buff_position--;
				}
				// roll-back cursor to previous line and delete character
				if (prompt_line>0) {
					if (prompt_line>0 && ((buff_position+_prompt_info.prompt_len-1) == (prompt_line)*COLS))
						prompt_line--;
					vga_text_mode_putc(kbrd_key_to_ascii(key));
					if (buff_position>0)
						buff_position--;
				}
				break;
			default :
				if (isascii(key)) {
					if (buff_position <= max_len_com_buffer-1) {
						command_buffer[buff_position++] = kbrd_key_to_ascii(key);
						if (prompt_line>0 && ((buff_position+_prompt_info.prompt_len-2) == (prompt_line+1)*COLS))
							prompt_line++;
						if (prompt_line==0 && (buff_position+_prompt_info.prompt_len-1 > COLS))
							prompt_line++;
						vga_text_mode_putc(kbrd_key_to_ascii(key));
					}
				}
		}
	}
}

bool tsh_exec() {
	bool ret_value = false;
	if (strcmp(&command_buffer, "kheap")==0) {
		kheap_status();
		return true;
	} else if (strcmp(&command_buffer, "kheaptest")==0) {
		kheap_test();
		return true;
	} else if (strcmp(&command_buffer, "ata")==0) {
		ata_show_info();
		return true;
	} else if (strcmp(&command_buffer, "pci")==0) {
		pci_show_info();
		return true;
	} else if (strcmp(&command_buffer, "atatest")==0) {
		ata_rw_test(0);
		return true;
	} else if (strcmp(&command_buffer, "proc")==0) {
		proc_info();
		return true;
	} else if (strcmp(&command_buffer, "kill")==0) {
		proc_kill(1);
		return true;
	} else if (strcmp(&command_buffer, "reset")==0) {
		kbrd_reset_system();
		return true;
	} else if (strcmp(&command_buffer, "help")==0) {
		tiny_shell_help();
		return true;
	}
	return ret_value;
}
